package com.star.uc.factory.login;

import com.alibaba.fastjson2.JSON;
import com.star.common.core.context.ThreadContext;
import com.star.common.core.contract.constant.ContextConstants;
import com.star.common.core.contract.enums.StatusEnum;
import com.star.common.core.contract.exception.ServiceException;
import com.star.common.core.utils.BizAssert;
import com.star.uc.contract.dto.request.LoginRequest;
import com.star.uc.contract.enums.UserErrorEnum;
import com.star.uc.contract.enums.UserStatusEnum;
import com.star.uc.contract.enums.uid.GeneratorUidTypeEnum;
import com.star.uc.contract.param.UserInfoParam;
import com.star.uc.contract.param.UserOuterMapperInfoParam;
import com.star.uc.contract.param.UserThirdConfigParam;
import com.star.uc.contract.query.RenderAuthQuery;
import com.star.uc.infras.repository.model.UserInfoBO;
import com.star.uc.infras.repository.model.UserOuterMapperInfoBO;
import com.star.uc.infras.repository.model.UserThirdConfigBO;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;

import java.util.Objects;

/**
 * 登录类型抽象业务处理类
 *
 * @author zhouhengzhe
 * @version 1.0
 * @date 2023/10/19 17:30
 */
@Slf4j
public abstract class AbstractLoginTypeOperator implements LoginTypeOperator {

    /**
     * 检查对应的登录类型的参数
     *
     * @param loginRequest 登录信息
     */
    @Override
    public void checkParam(LoginRequest loginRequest) {
        BizAssert.notBlankWarn(loginRequest.getCode(), UserErrorEnum.CODE_NULL);
        BizAssert.notBlankWarn(loginRequest.getState(), UserErrorEnum.STATE_NULL);
    }


    /**
     * 登录
     *
     * @param loginRequest 登录请求
     * @return 用户信息
     */
    @Override
    public UserInfoBO authorize(LoginRequest loginRequest) {
        //校验参数
        this.checkParam(loginRequest);
        //获取三方登录的参数信息
        AuthRequest authRequest = this.getAuthRequest(loginRequest.getTenantId(),
                loginRequest.getClientType(),
                loginRequest.getLoginType());
        //调取三方登录
        AuthResponse authResponse = authRequest.login(this.getAuthCallback(loginRequest));
        AuthUser data = (AuthUser) authResponse.getData();
        //3、获取第三方绑定信息
        UserOuterMapperInfoBO userOuterMapperInfoBO = UserOuterMapperInfoParam
                .builder()
                .tenantId(loginRequest.getTenantId())
                .identifier(data.getUuid())
                .loginType(this.getName())
                .build().one();
        //4、用户不存在创建新账号
        UserInfoBO userInfoBO;
        if (Objects.isNull(userOuterMapperInfoBO)) {
            //4.1、创建用户信息
            userInfoBO = this.createUser(loginRequest, data);
            //4.1.1、事务问题，需要先保存用户信息，然后再创建用户映射
            this.createUserMapping(userInfoBO.getUid(), loginRequest, data);
        } else {
            //4.2、用户存在，获取用户信息
            userInfoBO = UserInfoParam.builder().uid(userOuterMapperInfoBO.getUid()).build().one();
        }
        //判断当前用户是否不存在或者被禁用
        return checkUserInfoExistOrDisable(userInfoBO, loginRequest);
    }

    /**
     * 检查用户是否存在或者禁用
     *
     * @param userInfoBO   用户信息
     * @param loginRequest 请求参数
     * @return 用户信息
     */
    public UserInfoBO checkUserInfoExistOrDisable(UserInfoBO userInfoBO, LoginRequest loginRequest) {
        //判断用户是否存在
        if (Objects.isNull(userInfoBO)) {
            log.error("登录失败，用户不存在，参数为:{}", JSON.toJSONString(loginRequest));
            throw new ServiceException(UserErrorEnum.USER_NOT_EXIST);
        }
        //判断用户是否被禁用了,兼容下其他方式得禁用
        if (UserStatusEnum.DISABLE.getCode().equals(userInfoBO.getStatus())) {
            log.error("登录失败，用户被禁用，参数为:{}", JSON.toJSONString(loginRequest));
            throw new ServiceException(UserErrorEnum.USER_DISABLE);
        }
        return userInfoBO;
    }

    /**
     * 创建用户
     *
     * @param loginRequest 登录请求信息
     * @param authUser     第三方响应信息
     * @return 用户信息
     */
    @Override
    public UserInfoBO createUser(LoginRequest loginRequest, AuthUser authUser) {
        //创建用户
        return UserInfoBO
                .builder()
                .uid(GeneratorUidTypeEnum.getUidByType())
                .tenantId(loginRequest.getTenantId())
                .nickName(authUser.getNickname())
                .realName(authUser.getUsername())
                .avatar(authUser.getAvatar())
                .areaCode(ThreadContext.get(ContextConstants.AREA_CODE))
                .status(UserStatusEnum.NORMAL.getCode())
                .build();
    }

    /**
     * 创建用户映射
     *
     * @param uid          用户ID
     * @param loginRequest 登录请求
     * @param authUser     第三方响应信息
     * @return 用户映射信息
     */
    @Override
    public void createUserMapping(String uid, LoginRequest loginRequest, AuthUser authUser) {
        UserOuterMapperInfoBO
                .builder()
                .uid(uid)
                .loginType(loginRequest.getLoginType())
                .tenantId(loginRequest.getTenantId())
                .identifier(authUser.getUuid())
                .build().save();
    }

    /**
     * 获取授权地址
     *
     * @param renderAuthQuery 授权参数
     * @return 授权地址
     */
    @Override
    public String getAuthorizeUrl(RenderAuthQuery renderAuthQuery) {
        AuthRequest authRequest = getAuthRequest(renderAuthQuery.getTenantId(),
                renderAuthQuery.getClientType(),
                renderAuthQuery.getLoginType());
        return authRequest.authorize(AuthStateUtils.createState());
    }

    /**
     * 获取请求三方的配置
     *
     * @param tenantId   租户ID
     * @param clientType 客户端类型
     * @param thirdType  第三方类型
     * @return 请求三方的配置
     */
    public UserThirdConfigBO getUserThirdConfig(String tenantId, String clientType, String thirdType) {
        //获取三方配置
        return UserThirdConfigParam
                .builder()
                .tenantId(tenantId)
                .thirdType(thirdType)
                .clientType(clientType)
                .status(StatusEnum.OPEN.getCode())
                .build()
                .one(UserErrorEnum.THIRD_CONFIG_NOT_EXIST);
    }
    /**
     * 获取授权回调信息
     *
     * @param loginRequest 登录请求
     * @return 授权回调信息
     */
    @Override
    public AuthCallback getAuthCallback(LoginRequest loginRequest) {
        return AuthCallback.builder()
                .code(loginRequest.getCode())
                .state(loginRequest.getState())
                .build();
    }

    /**
     * 获取授权请求参数
     *
     * @param tenantId   租户ID
     * @param clientType 客户端类型
     * @param thirdType  第三方类型
     * @return 授权请求参数
     */
    @Override
    public AuthRequest getAuthRequest(String tenantId, String clientType, String thirdType) {
        return null;
    }
}
